package cn.tannn.ops.ssh.pojo;

import lombok.Data;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 端口使用详情
 *
 * @author <a href="https://t.tannn.cn/">tan</a>
 * @version V1.0
 * @date 2024/12/26 14:17
 */
@Data
public class UsePortInfo {
    /**
     * 协议
     */
    private String protocol;
    /**
     * 每个连接的状态
     */
    private String state;
    /**
     * 本地IP地址
     */
    private String localAddress;
    /**
     * 本地端口
     */
    private int port;

    /**
     * 端口的进程
     */
    private String process;

    /**
     * pid
     */
    private int pid;
    /**
     * 存储所有进程
     */
    private List<String> processes;

    /**
     * 存储 JAR 文件名
     */
    private String jarName;


    /**
     * 解析端口信息行
     *
     * @param line 命令输出的一行
     * @return 返回 UsePortInfo 对象
     */
    public static UsePortInfo parsePortInfo(String line) {
        // 使用正则表达式解析每行
        // 示例行: tcp  LISTEN  0      128    0.0.0.0:22        0.0.0.0:*    users:(("sshd",pid=1256,fd=3))
//        Pattern pattern = Pattern.compile("(?<protocol>\\S+)\\s+(?<state>\\S+)\\s+(?<recvQ>\\S+)\\s+(?<sendQ>\\S+)\\s+(?<localAddress>\\S+):(\\d+)\\s+.*\\s+users:\\(\\(\\\"(?<process>\\S+)\",pid=(?<pid>\\d+),fd=\\d+\\)\\)");
        Pattern pattern = Pattern.compile("(?<protocol>\\S+)\\s+(?<state>\\S+)\\s+(?<recvQ>\\S+)\\s+(?<sendQ>\\S+)\\s+(?<localAddress>\\S+):(\\d+)\\s+.*\\s+users:\\((?<process>.*)\\)");

        Matcher matcher = pattern.matcher(line);

        if (matcher.find()) {
            UsePortInfo usePortInfo = new UsePortInfo();
            usePortInfo.setProtocol(matcher.group("protocol"));
            usePortInfo.setState(matcher.group("state"));
            usePortInfo.setLocalAddress(matcher.group("localAddress"));
            usePortInfo.setPort(Integer.parseInt(matcher.group(6))); // 提取端口号
            // 处理进程信息，特别是多个进程的情况
            String processStr = matcher.group("process");
            List<String> processes = extractProcesses(processStr);
            usePortInfo.setProcesses(processes);
            // 判断是单个进程还是多个进程
            if (processes.size() == 1) {
                // 单个进程，正常处理
                String process = processes.get(0);
                usePortInfo.setProcess(process.split(",")[0]);
                usePortInfo.setPid(Integer.parseInt(process.split(",")[1].split("=")[1]));
            } else if (processes.size() > 1) {
                // 多个进程的情况，特殊处理
                usePortInfo.setProcess(processes.get(0)); // 设置第一个进程的名字
                String pidStr = processes.get(0).split(",")[1].split("=")[1];
                usePortInfo.setPid(Integer.parseInt(pidStr)); // 只设置第一个进程的 pid
            }
            return usePortInfo;
        }
        return null;
    }


    /**
     * 从 users 字段中提取多个进程信息
     * @param processStr users 字段的内容
     * @return 进程列表
     */
    private static List<String> extractProcesses(String processStr) {
        List<String> processes = new ArrayList<>();

        // 正则表达式用于提取以下格式的进程信息:
        // 1. ("processName",pid=xxx,fd=xxx)
        // 2. ("processName",pid,fd)
        Pattern pattern = Pattern.compile("\\(\"([^\"]+)\",([^,]+),([^,]+)\\)");
        Matcher matcher = pattern.matcher(processStr);

        while (matcher.find()) {
            String processName = matcher.group(1); // 进程名
            String pid = matcher.group(2); // 进程ID（可能是带等号的，也可能没有）
            String fd = matcher.group(3); // 文件描述符

            // 如果 pid 不是带等号的形式（即只有一个数字），我们假设它是 PID
            if (pid.startsWith("pid=")) {
                pid = pid.split("=")[1];
            }

            // 组装进程信息，格式为 "processName,pid=xxx"
            processes.add(processName + ",pid=" + pid + ",fd=" + fd);
        }
        return processes;
    }
}
